package com.opNaga.bpmn.palettes;

import y.geom.YDimension;
import y.view.*;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class AbilityPalette extends JComponent {
    private static final String RESOURCE_PATH = "./resource/ide/image";
    private DragAndDropSupport dropSupport;

    public AbilityPalette(final Graph2DView view) {
        final BorderLayout borderLayout = new BorderLayout();
        borderLayout.setVgap(10);
        this.setLayout(borderLayout);
        this.add(createDefaultPalette(view), BorderLayout.CENTER);
        initializeDefaultRealizers(view);
    }

    protected void initializeDefaultRealizers(Graph2DView view) {
        Graph2D graph = view.getGraph2D();
        final EdgeRealizer der = graph.getDefaultEdgeRealizer();
        if (der instanceof PolyLineEdgeRealizer) {
            ((PolyLineEdgeRealizer) der).setSmoothedBends(true);
            der.setTargetArrow(Arrow.STANDARD);
        }
    }

    private JComponent createDefaultPalette(final Graph2DView view) {
        List configurations = createConfigurations();
        List realizerList = createRealizers(configurations);
        JList dragAndDropList = new DragAndDropSupport(realizerList, view).getList();
        dragAndDropList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        return new JScrollPane(dragAndDropList);
    }

    protected List createConfigurations() {
        List<String> configNames = new ArrayList<String>();
        GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();

        String configName = "Decorated Rect";
        factory.addConfiguration(configName, createDecoratedRectPainterConfiguration(factory));
        configNames.add(configName);

        return configNames;
    }

    private List createRealizers(List configurations) {
        List realizers = new ArrayList(configurations.size());
        for (Object configuration : configurations) {
            String configName = String.valueOf(configuration);
            GenericNodeRealizer nr = new GenericNodeRealizer(configName);
            nr.setLabelText(configName);
            nr.setWidth(120);
            nr.setFillColor(Color.ORANGE);

            NodeLabel label = nr.getLabel();
            SmartNodeLabelModel model = new SmartNodeLabelModel();
            label.setLabelModel(model);
            label.setModelParameter(model.getDefaultParameter());

            label.setModelParameter(model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_LEFT));

            realizers.add(nr);
        }

        return realizers;
    }

    private Map createDecoratedRectPainterConfiguration(GenericNodeRealizer.Factory factory) {
        Map implementationsMap = factory.createDefaultConfigurationMap();
        IconDecoratorPainter painter = new IconDecoratorPainter(new RectangularShapePainter(new RoundRectangle2D.Double(50, 50, 50, 50, 15, 15)));
        implementationsMap.put(GenericNodeRealizer.Painter.class, new ShadowNodePainter(painter));
        return implementationsMap;
    }

    public static final class RectangularShapePainter extends AbstractCustomNodePainter implements GenericNodeRealizer.ContainsTest {
        private RectangularShape shape;

        public RectangularShapePainter(RectangularShape shape) {
            this.shape = shape;
        }

        protected Color getFillColor(NodeRealizer context, boolean selected) {
            if (selected) {
                return Color.red;
            } else {
                return super.getFillColor(context, selected);
            }
        }

        protected void paintNode(NodeRealizer context, Graphics2D graphics, boolean sloppy) {
            shape.setFrame(context.getX(), context.getY(), context.getWidth(), context.getHeight());
            if (initializeFill(context, graphics)) {
                graphics.fill(shape);
            }
            if (initializeLine(context, graphics)) {
                graphics.draw(shape);
            }
        }

        public boolean contains(NodeRealizer context, double x, double y) {
            shape.setFrame(context.getX(), context.getY(), context.getWidth(), context.getHeight());
            return shape.contains(x, y);
        }
    }

    static class IconDecoratorPainter implements GenericNodeRealizer.Painter {
        private final GenericNodeRealizer.Painter innerPainter;
        private Icon icon;

        public IconDecoratorPainter(GenericNodeRealizer.Painter innerPainter) {
            this.innerPainter = innerPainter;
            icon = createIcon();
        }

        public void paint(final NodeRealizer context, final Graphics2D graphics) {
            innerPainter.paint(context, graphics);
            paintIcon(context, graphics);
        }

        public void paintSloppy(final NodeRealizer context, final Graphics2D graphics) {
            innerPainter.paintSloppy(context, graphics);
            paintIcon(context, graphics);
        }

        private void paintIcon(final NodeRealizer context, final Graphics2D graphics) {
            int x = (int) (context.getX() + context.getWidth() - icon.getIconWidth() - 2);
            int y = (int) (context.getY() + 2);
            icon.paintIcon(null, graphics, x, y);
        }

        protected Icon createIcon() {
            final ImageIcon imageIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(RESOURCE_PATH + "/redo.png"));
            final double zoom = 16.0d / Math.min(imageIcon.getIconHeight(), imageIcon.getIconWidth());

            return new Icon() {
                public void paintIcon(Component c, Graphics g, int x, int y) {
                    g.drawImage(imageIcon.getImage(), x, y, getIconWidth(), getIconHeight(), null);
                }

                public int getIconWidth() {
                    return (int) (imageIcon.getIconWidth() * zoom);
                }

                public int getIconHeight() {
                    return (int) (imageIcon.getIconHeight() * zoom);
                }
            };
        }
    }
}